//
// Created by 28365 on 2025/3/14.
//

#include "../include/config/proceessing/record/DefaultUpdateRecorder.h"
#include "../include/exception/FileReadException.h"
#include "../include/exception/FileTypeException.h"
#include "../include/exception/ExistingVersionUseException.h"
#include "../include/exception/VersionUnUseException.h"
#include "../include/exception/FileWriteExcpetion.h"
#include <cstring>
#include "../include/utils/VersionUtils.hpp"

typedef uint64_t header_size;
/**
 * 默认更新记录器
 * <p>数据记录格式：
 * <p>4byte - 最后一次 已更新完成的版本号
 * <p>4byte - 最后一次 未更新完成的版本号
 * <p>8byte - 最后一次版本已更新完成的资源id
 * <p>... - 往后每8byte记录一次已完成更新的资源id
 */
UpdateRecord DefaultUpdateRecorder::getUpdatedVersion(const ODUpdater &_odUpdater) {

    File file(_odUpdater.getRootDirectory() + "/" + fileName);

    if (!file.isExists()){
        return {0,0,set<int64_t>()};
    }

    UpdateRecord result;

    ifstream *inStream;
    try {
       inStream = file.openInStream(std::ios::binary);

        header_size header = 0;
        set<int64_t> resIds;

        char buf[8];
        size_t len;
        do {
            inStream->read(buf,8);
            len = inStream->gcount();

            if (len == 0){
                break;
            }

            if (len != 8){
                continue;
            }

            //读取文件数据头
            if (header == 0){
                memcpy(&header,buf,8);
                continue;
            }

            //读取已完成的资源id
            int64_t id;
            memcpy(&id, buf, 8);
            resIds.emplace(id);

        } while (true);

        int version = 0;
        memcpy(&version, &header, 4);
        int notCompletedVersion = 0;
        memcpy(&notCompletedVersion, reinterpret_cast<char*>(&header) + 4, 4);
        result = UpdateRecord(version,notCompletedVersion,resIds);

    }catch (exception &e){
        throw FileReadException(string("文件读取出错！->") + e.what());
    }

    if (inStream->is_open()){
        inStream->close();
    }

    return result;
}

void DefaultUpdateRecorder::useVersion(const ODUpdater *_odUpdater, int version) {
    if (isUseVersion()){
        throw ExistingVersionUseException("当前已存在指定版本，不能再次指定，请先调用complete()或closeStream()结束当前版本的操作");
    }

    this->odUpdater = _odUpdater;
    if (versionFile == nullptr){
        versionFile = new File(odUpdater->getRootDirectory() + "/" + fileName);
    }
    ifstream *inStream = nullptr;

    try {
        if (versionFile->isExists()){
            odUpdater->getLogger()->debug("加载本地记录数据头");
            inStream = versionFile->openInStream();

            //文件头
            char header[8];
            inStream->read(header,8);
            if (inStream->gcount() < 8){
                throw FileTypeException("文件类型异常");
            }

            //未完成更新的版本
            int unCompleteVersion = 0;
            memcpy(&unCompleteVersion,reinterpret_cast<char*>(&header) + 4,4);

            /*
                上次更新未完成的版本是否与当前指定的版本相同
                没有未完成的版本或者未完成的版本与指定版本不同时 - 覆盖上次记录的资源id
                存在未完成版本，而且版本与当前指定的版本相同时 - 续上次更新累加资源id
            */
            if (unCompleteVersion != version){
                odUpdater->getLogger()->debug("可能不存在未完成更新的版本->覆盖旧数据");
                outStream = versionFile->openOutStream();
                char v[4];
                memcpy(v,&version,4);
                outStream->write(v,4);
                outStream->flush();
            } else{
                outStream = versionFile->openOutStream(std::ios::app);
            }

            inStream->close();
        } else{
            odUpdater->getLogger()->debug("未找到版本记录文件-->新建文件");
            if (!versionFile->existsParentDir() && !versionFile->mkParentDirs()){
                throw FileReadException("无法创建父级文件夹！");
            }

            outStream = versionFile->openOutStream();

            //初始化当前版本状态，最后一次完成更新的版本号设为0，未完成更新的版本号设为当前正在更新的版本
            char header[8] = {0,0,0,0};
            memcpy(reinterpret_cast<char*>(&header) + 4,&version,4);
            outStream->write(header,8);
            outStream->flush();
        }
    }catch (exception &e){
        throw FileReadException(string("文件读取出错！") + e.what());
    }
    if (inStream != nullptr && inStream->is_open()){
        inStream->close();
    }

    this->nowVersion = version;
}

void DefaultUpdateRecorder::addRes(int64_t resId) {
    if (!isUseVersion()){
        throw VersionUnUseException("没有指定版本");
    }

    try{
        std::lock_guard<std::mutex> lock(fileMutex);
        char buf[8];
        memcpy(buf,&resId,8);
        outStream->write(buf,8);
        tryFlush();
        odUpdater->getLogger()->debug("记录更新-->资源id" + to_string(resId));
    }catch (exception &e){
        throw FileWriteException(string("文件写入出错！") + e.what());
    }
}

void DefaultUpdateRecorder::complete() {

    if (isUseVersion()){
        try {
            std::lock_guard<std::mutex> lock(fileMutex);
            outStream->close();
            char header[8];
            memset(header,0,8);
            memcpy(header,&nowVersion,4);

            /*
            重写更新文件数据
            文件头：
                最后一次更新完成的版本 = 当前指定的版本
                未完成的版本 = 0
            资源id:无数据
            */
            ofstream *completeOutStream = versionFile->openOutStream();
            completeOutStream->write(header,8);
            completeOutStream->close();

            odUpdater->getLogger()->debug("完成记录-->[v" + version::intToVersion(nowVersion) + "]");
        }catch (exception &e){
        }
        this->nowVersion = 0;
    } else{
        throw VersionUnUseException("没有指定版本");
    }
}

void DefaultUpdateRecorder::closeStream() {
    if (outStream != nullptr){
        std::lock_guard<std::mutex> lock(fileMutex);
        try {
            odUpdater->getLogger()->debug("中断记录-->[v" + version::intToVersion(nowVersion) + "]");
            outStream->close();
        }catch (exception &e){
        }
        this->nowVersion = 0;
    }
}

bool DefaultUpdateRecorder::isUseVersion() {
    return this->nowVersion != 0;
}

DefaultUpdateRecorder::~DefaultUpdateRecorder(){
    delete versionFile;
}

void DefaultUpdateRecorder::tryFlush() {
    auto now = std::time(nullptr);
    if (now - lastFlush >= 1){
        lastFlush = now;
        outStream->flush();
    }
}

DefaultUpdateRecorder::DefaultUpdateRecorder() = default;
